package com.robotic.sensor.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException; // 导入
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;

@Component
public class ModbusTcpGasServer {
    private static final Logger log = LoggerFactory.getLogger(ModbusTcpGasServer.class);

    // 1. 配置参数
    private static final int LISTEN_PORT = 8898;
    private static final String LISTEN_HOST = "192.168.201.73";
    private static final String HEX_COMMAND = "010300000002C40B";
    private static final int POLLING_INTERVAL_MS = 5000; // 每5秒查询一次设备
    private static final int SERVER_RETRY_DELAY_MS = 5000; // 服务器重启延迟

    // ... 线程池定义 ...
    private final ExecutorService serverExecutor = Executors.newSingleThreadExecutor();
    private final ExecutorService clientExecutor = Executors.newCachedThreadPool();

    private ServerSocket serverSocket;

    // ... 原子引用 ...
    private final AtomicReference<String> latestGas = new AtomicReference<>();

    @PostConstruct
    public void startServer() {
        serverExecutor.submit(() -> {
            // 【优化点 1】添加一个外层循环，以便在ServerSocket失败时可以重建
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    // 1. 尝试创建 ServerSocket
                    serverSocket = new ServerSocket(LISTEN_PORT, 1, java.net.InetAddress.getByName(LISTEN_HOST));
                    log.info("气体 TCP 服务器已在 {}:{} 启动", LISTEN_HOST, LISTEN_PORT);

                    // 2. 正常的 accept 循环
                    while (!Thread.currentThread().isInterrupted() && !serverSocket.isClosed()) {
                        try {
                            log.info("等待模块连接...");
                            Socket clientSocket = serverSocket.accept();
                            log.info("模块已连接! 地址: {}", clientSocket.getRemoteSocketAddress());

                            // 为每个连接的客户端启动一个独立的、持续处理的线程
                            clientExecutor.submit(() -> handleClient(clientSocket));
                        } catch (IOException e) {
                            // accept() 失败
                            if (serverSocket != null && !serverSocket.isClosed()) {
                                log.warn("接受新连接时发生IO异常: {}", e.getMessage());
                                // 稍作等待，避免CPU空转
                                Thread.sleep(1000);
                            } else {
                                // ServerSocket 被外部关闭 (e.g., @PreDestroy)
                                log.info("服务器Socket已关闭，停止接受新连接。");
                            }
                        }
                    }
                } catch (IOException e) {
                    // new ServerSocket() 失败 (e.g., 端口占用, IP无效)
                    log.error("服务器Socket未能启动 ({} at {}:{}): {}", e.getMessage(), LISTEN_HOST, LISTEN_PORT);
                } catch (InterruptedException e) {
                    // Thread.sleep(1000) 被中断
                    log.warn("服务器 'accept' 等待时被中断");
                    Thread.currentThread().interrupt(); // 重新设置中断状态
                }

                // 3. 如果我们跳出了内部循环 (e.g., ServerSocket.close() 被调用),
                //    或者 ServerSocket 创建失败, 我们会到达这里。
                //    在重试前等待一段时间。
                if (!Thread.currentThread().isInterrupted()) {
                    try {
                        log.info("气体服务器将在 {}ms 后尝试重启...", SERVER_RETRY_DELAY_MS);
                        Thread.sleep(SERVER_RETRY_DELAY_MS);
                    } catch (InterruptedException e) {
                        log.warn("服务器重启等待时被中断，退出。");
                        Thread.currentThread().interrupt(); // 重新设置中断状态
                    }
                }
            } // end of while (!Thread.currentThread().isInterrupted())
            log.info("气体服务器监听主线程已停止。");
        });
    }

    private void handleClient(Socket clientSocket) {
        // 使用 try-with-resources 确保 socket 在线程结束时被关闭
        try (InputStream in = clientSocket.getInputStream();
             OutputStream out = clientSocket.getOutputStream()) {

            byte[] commandBytes = hexStringToByteArray(HEX_COMMAND);
            byte[] buffer = new byte[64];
            clientSocket.setSoTimeout(5000); // 5秒读取超时

            // 【优化点 2】更鲁棒的循环条件
            while (clientSocket.isConnected() && !clientSocket.isClosed() && !Thread.currentThread().isInterrupted()) {
                try {
                    //log.info("向模块 {} 发送指令: {}", clientSocket.getRemoteSocketAddress(), HEX_COMMAND);
                    out.write(commandBytes);
                    out.flush();

                    // 读取响应
                    int bytesRead = in.read(buffer);

                    // 【优化点 3】处理-1 (客户端主动断开)
                    if (bytesRead == -1) {
                        log.warn("模块 {} 优雅地关闭了连接。", clientSocket.getRemoteSocketAddress());
                        break; // 退出循环
                    }

                    if (bytesRead > 0) {
                        byte[] responseBytes = Arrays.copyOf(buffer, bytesRead);
                        parseGasResponse(responseBytes);
                    }

                    // 等待下一个轮询周期
                    Thread.sleep(POLLING_INTERVAL_MS);

                } catch (SocketTimeoutException e) {
                    log.warn("模块 {} 读取响应超时", clientSocket.getRemoteSocketAddress());
                    // 超时是正常的，继续下一次轮询
                }
            }
        } catch (IOException e) {
            log.warn("与模块 {} 的连接丢失: {}", clientSocket.getRemoteSocketAddress(), e.getMessage());
        } catch (InterruptedException e) {
            log.warn("客户端处理线程被中断");
            Thread.currentThread().interrupt(); // 重新设置中断状态
        } finally {
            log.info("模块 {} 的连接已关闭", clientSocket.getRemoteSocketAddress());
        }
    }

    /**
     * 解析气体探测器的响应数据
     * @param responseBytes 从设备收到的原始字节数组
     */
    private void parseGasResponse(byte[] responseBytes) {
        // --- 尝试解析响应 ---
        // 预期响应 (2个寄存器 = 4字节数据): 01 03 04 [数据1高] [数据1低] [数据2高] [数据2低] [CRC高] [CRC低]
        // 文档示例: 01 03 04 00 02 01 21 8A 7B
        if (responseBytes.length < 9) { // 1(ID)+1(Func)+1(Count)+4(Data)+2(CRC) = 9 字节
            System.out.println("响应太短，无法解析。");
            return;
        }

        if (responseBytes[0] != 0x01 || responseBytes[1] != 0x03) {
            System.out.println("响应头不是 0103。");
            return;
        }

        int byteCount = responseBytes[2] & 0xFF;
        if (byteCount != 4) {
            System.out.printf("期望4个数据字节，但响应中声明有 %d 个。\n", byteCount);
            return;
        }

        // 检查总长度是否匹配: 3 (Header) + byteCount + 2 (CRC)
        if (responseBytes.length != 5 + byteCount) {
            System.out.printf("响应总长度 %d 与数据字节数 %d 不匹配。\n", responseBytes.length, byteCount);
            return;
        }

        // 提取数据
        byte[] dataBytes = Arrays.copyOfRange(responseBytes, 3, 3 + byteCount);

        // 寄存器 40001 (状态)
        int decimalByte = dataBytes[0] & 0xFF; // 高字节
        int statusByte = dataBytes[1] & 0xFF;   // 低字节

        // 寄存器 40002 (浓度)
        int concentrationValue = ((dataBytes[2] & 0xFF) << 8) | (dataBytes[3] & 0xFF);

        // --- 解析状态 ---
        int decimalPlaces;
        String statusStr;

        switch (decimalByte) {
            case 0x01: decimalPlaces = 1; break; // 1位小数
            case 0x02: decimalPlaces = 2; break; // 2位小数
            default:   decimalPlaces = 0; break; // 整数
        }

        switch (statusByte) {
            case 0x01: statusStr = "报警"; break;
            case 0x02: statusStr = "故障"; break;
            default:   statusStr = "正常"; break;
        }

        // --- 计算浓度 ---
        double divisor = Math.pow(10, decimalPlaces);
        double finalConcentration = (double) concentrationValue / divisor;

        /*System.out.println("--- 响应解析 (气体探测器) ---");
        System.out.printf("  状态寄存器 (原始值): 0x%02X%02X\n", decimalByte, statusByte);
        System.out.printf("  探测器状态: %s\n", statusStr);
        System.out.printf("  浓度小数位数: %d\n", decimalPlaces);
        System.out.printf("  浓度寄存器 (原始值): %d\n", concentrationValue);

        // 格式化输出，确保小数位数正确
        String formatString = "  >>> 最终浓度: %." + decimalPlaces + "f\n";*/
        this.latestGas.set("检测状态：" + statusStr + "，气体浓度为：" + concentrationValue);
        log.info("getLatestGas ================== {}", getLatestGas());
    }

    public String getLatestGas() {
        return this.latestGas.get();
    }

    @PreDestroy
    public void stopServer() {
        log.info("正在关闭 Modbus TCP 服务器...");
        try {
            if (serverSocket != null && !serverSocket.isClosed()) {
                serverSocket.close();
            }
        } catch (IOException e) {
            log.error("关闭服务器Socket时出错", e);
        }
        // 优雅地关闭线程池
        serverExecutor.shutdown();
        clientExecutor.shutdown();
        log.info("服务器已关闭。");
    }

    // --- 辅助方法 ---
    private static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i + 1), 16));
        }
        return data;
    }

    private static String bytesToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
}
